package keer.httpinterface.http;

import keer.httpinterface.utils.IOUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;

/**
 * 基于{@link HttpURLConnection}实现的{@link HttpRequester}，使用{@link HttpURLConnection}实现http请求发送和响应数据接收
 * @see HttpRequester
 * @see AbstractHttpRequester
 * @see HttpProperties
 * @see HttpRequest
 * @see HttpResponse
 * @see HttpURLConnection
 *
 * @author Keer
 * @since 1.0.0
 */
public final class URLHttpRequester extends AbstractHttpRequester {

    private HttpProperties properties;

    @Override
    protected void configure0(HttpProperties properties) throws Exception {
        this.properties = properties;
        System.setProperty("http.keepAlive", "true");
        System.setProperty("http.maxConnections", String.valueOf(properties.getMaxConnections()));
    }

    @Override
    protected HttpResponse request0(HttpRequest request) throws Exception {
        if (request.getMethod().isHasBody()) {
            return doRequest(request.getUrl(), request.getMethod(), request.getHeaders(), request.getBody());
        }
        return doRequest(request.getUrl(), request.getMethod(), request.getHeaders(), null);
    }

    private HttpResponse doRequest(String url, HttpMethod method, Headers headers, HttpBody body) throws IOException {
        URL u = new URL(url);
        HttpURLConnection connection = (HttpURLConnection) u.openConnection();
        connection.setDoInput(Boolean.TRUE);
        connection.setDoOutput(Boolean.TRUE);
        connection.setUseCaches(Boolean.FALSE);
        connection.setConnectTimeout(properties.getConnectTimeoutMillis().intValue());
        connection.setReadTimeout(properties.getReadTimeoutMillis().intValue());
        connection.setRequestMethod(method.name());
        for (String key : headers.all().keySet()) {
            List<String> values = headers.all().get(key);
            if (values != null) {
                for (String v : values) {
                    connection.setRequestProperty(key, v);
                }
            }
        }
        if (body != null) {
            OutputStream out = connection.getOutputStream();
            IOUtils.copy(body, out);
        }
        InputStream content = connection.getInputStream();
        InputStream errorContent = connection.getErrorStream();
        int code = connection.getResponseCode();
        Headers respHeaders = new Headers(connection.getHeaderFields());
        HttpResponse.Builder builder = HttpResponse.builder();
        builder.headers(respHeaders)
                .connection(()->{
                    IOUtils.closeQuietly(content);
                    IOUtils.closeQuietly(errorContent);
                })
                .statusCode(code)
                .content(content)
                .error(errorContent)
                .message(connection.getResponseMessage())
                .contentEncoding(connection.getContentEncoding())
                .contentLength(connection.getContentLengthLong())
                .version(connection.getHeaderField(null))
                .contentType(connection.getContentType());
        return builder.build();
    }
}
